#pragma once

/** This is a macro that casts a dynamically bound RHI reference to the appropriate D3D type. */
#define DYNAMIC_CAST_D3D9RESOURCE(Type,Name) \
	FD3D9##Type* Name = (FD3D9##Type*)Name##RHI;

#include "DynamicRHI.h"

#include "D3D9Util.h"
#include "D3D9Resources.h"
#include "D3D9State.h"
#include "D3D9RenderTarget.h"
#include "D3D9Viewport.h"


namespace RenderSystem
{
	class ViewPort;
	class RenderTarget;

	class FD3D9DynamicRHI
		: public FDynamicRHI
	{
	public:
		FD3D9DynamicRHI(void);
		virtual ~FD3D9DynamicRHI(void);

		#define DEFINE_RHIMETHOD(Type,Name,ParameterTypesAndNames,ParameterNames,ReturnStatement,NullImplementation) virtual Type Name ParameterTypesAndNames
		#include "RHIMethods.h"
		#undef DEFINE_RHIMETHOD

		
		// Reference counting API for the different resource types.
#define IMPLEMENT_FDynamicRHI_REFCOUNTING_FORTYPE(Type,ParentType) \
	virtual void AddResourceRef(TFDynamicRHIResource<RRT_##Type>* ReferenceRHI) \
		{ \
			DYNAMIC_CAST_D3D9RESOURCE(Type,Reference); \
			Reference->AddRef(); \
		} \
		virtual void RemoveResourceRef(TFDynamicRHIResource<RRT_##Type>* ReferenceRHI) \
		{ \
			DYNAMIC_CAST_D3D9RESOURCE(Type,Reference); \
			Reference->Release(); \
		} \
		virtual DWORD GetRefCount(TFDynamicRHIResource<RRT_##Type>* ReferenceRHI) \
		{ \
			DYNAMIC_CAST_D3D9RESOURCE(Type,Reference); \
			Reference->AddRef(); \
			return Reference->Release(); \
		}
		ENUM_RHI_RESOURCE_TYPES(IMPLEMENT_FDynamicRHI_REFCOUNTING_FORTYPE);

#undef IMPLEMENT_FDynamicRHI_REFCOUNTING_FORTYPE

	private:

		bool _IsDeviceLost(void);
		D3DPRIMITIVETYPE _GetD3D9PrimitiveType(UINT uPrimitiveType);

	private:

		/** Information about a vertex stream that's been bound to the D3D device. */
		struct D3D9Stream
		{
			D3D9Stream(void)
				:uStride(0)
			{}

			FVertexBufferRHIParamRef pVertexBuffer;
			UINT uStride;
			UINT uNumVerticesPerInstance;
		};

		enum { NumVertexStreams = 16 };

		UINT		m_uPendingNumInstances;
		UINT		m_uUpdateStreamForInstancingMask;
		UINT		m_uNumVertexStreams;

		LPDIRECT3D9	m_pDirect3;
		LPDIRECT3DDEVICE9 m_pDirect3DDevice;

		D3D9Stream	m_PendingStreams[NumVertexStreams];

		DWORD		m_GPUFrameTime;

		typedef		std::vector<ViewPort*>		ViewPorts;
		ViewPorts	m_ViewPorts;

		// Current drawing viewport
		ViewPort*	m_pDrawingViewport;

		// Back buffer
		RenderTarget*	m_pBackBuffer;

		// Information about pending BeginDraw[Indexed]PrimitiveUP calls.
		bool m_bPendingBegunDrawPrimitiveUP;

		BYTE* m_PendingDrawPrimitiveUPVertexData;
		UINT m_uPendingNumVertices;
		UINT m_uPendingVertexDataStride;

		BYTE* m_PendingDrawPrimitiveUPIndexData;
		UINT m_uPendingPrimitiveType;
		UINT m_uPendingNumPrimitives;
		UINT m_uPendingMinVertexIndex;
		UINT m_uPendingIndexDataStride;
	};

	void VerifyD3D9CreateTextureResult(HRESULT D3DResult,const char* Code,const char* Filename,UINT Line,UINT SizeX,UINT SizeY,BYTE Format,UINT NumMips,DWORD Flags);
	void VerifyD3D9Result(HRESULT D3DResult,const char* Code,const char* Filename,UINT Line);
}